package met.cs664.ai.cox.soc;

import met.cs664.ai.cox.soc.strategies.InitialPlacement;
import soc.debug.D;
import soc.game.SOCBoard;
import soc.game.SOCGame;
import soc.game.SOCSettlement;
import soc.robot.SOCRobotBrain;
import soc.robot.SOCRobotClient;
import soc.util.CappedQueue;
import soc.util.SOCRobotParameters;

/**
 * An augmented brain providing configurable overrides of SOCRobotBrain functionality and decision making. Each override
 * may be enabled or disabled independently providing flexibility over which aspects of the brain are changed.
 *
 * Overrides not defined in this implementation will default to the SOCRobotBrain implementation. This allows for this
 * robot to selective override aspects of game play of interest while defaulting the remaining decision making to the
 * base robot.
 *
 * @author mcox
 */
public class Brain extends SOCRobotBrain {

    /** Override to placing the first two initial settlements */
    private boolean isPlacingInitialSettlements;

    /** The robot to which this brain is attached */
    private SOCRobotClient client;

    /** The game we are playing */
    private SOCGame game;

    /** Tracks when we have placed our first settlement */
    private boolean hasPlacedFirstSettlement;

    /** Tracks when we have placed our second settlement */
    private boolean hasPlacedSecondSettlement;

    /**
     * Build a brain with the required base parameters
     * @param robotClient Our robot client
     * @param robotParameters Game parameters for robots
     * @param game The game we are playing
     * @param queue The robot decision queue.
     */
    public Brain(SOCRobotClient robotClient, SOCRobotParameters robotParameters, SOCGame game, CappedQueue queue) {
        super(robotClient, robotParameters, game, queue);
        this.client = robotClient;
        this.game = game;
    }

    /**
     * Turn on/off the control over placing the initial settlements at game start
     * @param isPlacingInitialSettlements true to override initial settlement placement
     * @return this
     */
    public Brain placeInitialSettlements(boolean isPlacingInitialSettlements) {
        D.debug(String.format("isPlacingInitialSettlements is %b", isPlacingInitialSettlements));
        this.isPlacingInitialSettlements = isPlacingInitialSettlements;
        return this;
    }

    /**
     * Instantiate a initial placement strategy and place our first settlement
     */
    @Override
    protected void placeFirstSettlement() {
        if (isPlacingInitialSettlements) {
            SOCBoard board = game.getBoard();
            InitialPlacement initialPlacement = new InitialPlacement(board, ourPlayerData,
                    game.getCurrentPlayerNumber() == game.getLastPlayerNumber());

            synchronized (this) {
                if (!hasPlacedFirstSettlement) {
                    D.debug("Placing first settlement");
                    firstSettlement = initialPlacement.electFirstSettlement();
                    client.putPiece(game, new SOCSettlement(ourPlayerData, firstSettlement, null));
                    hasPlacedFirstSettlement = true;
                }
            }
        } else {
            D.debug("Placing first settlement " + firstSettlement);
            super.placeFirstSettlement();
        }
    }

    /**
     * Instantiate a initial placement strategy and place our second settlement
     */
    @Override
    protected void placeSecondSettlement() {
        if (isPlacingInitialSettlements) {
            SOCBoard board = game.getBoard();
            InitialPlacement initialPlacement = new InitialPlacement(board, ourPlayerData,
                    game.getCurrentPlayerNumber() == game.getLastPlayerNumber());

            synchronized (this) {
                if (!hasPlacedSecondSettlement) {
                    D.debug("Placing second settlement");
                    secondSettlement = initialPlacement.electSecondSettlement();
                    client.putPiece(game, new SOCSettlement(ourPlayerData, secondSettlement, null));
                    hasPlacedSecondSettlement = true;
                }
            }
        } else {
            D.debug("Placing first settlement " + secondSettlement);
            super.placeSecondSettlement();
        }
    }
}
